//*******************************************************************       //
//IMPORTANT NOTICE                                                          //
//================                                                          //
//Copyright Mentor Graphics Corporation 1996 - 1999.  All rights reserved.  //
//This file and associated deliverables are the trade secrets,              //
//confidential information and copyrighted works of Mentor Graphics         //
//Corporation and its licensors and are subject to your license agreement   //
//with Mentor Graphics Corporation.                                         //
//                                                                          //
//Use of these deliverables for the purpose of making silicon from an IC    //
//design is limited to the terms and conditions of your license agreement   //
//with Mentor Graphics If you have further questions please contact Mentor  //
//Graphics Customer Support.                                                //
//                                                                          //
//This Mentor Graphics core (m8051w v2002.080) was extracted on             //
//workstation hostid 8316cbec Inventra                                      //
// 8-Bit Arithmetic Logic Unit for M8051W/EW
// 
// $Log: m3s003dy.v,v $
// Revision 1.7  2001/11/20
// First checkin of version 2 features and name change
//
// Revision 1.2  2001/10/31
// First parsable verilog for EW
//
// Revision 1.1.1.1  2001/07/17
// Re-imported E-Warp from Farnham filesystem
//
// Revision 1.6  2000/12/13
// Unreachable X-handling states removed
//
// Revision 1.5  2000/10/24
// Multiplier rewritten to improve power consumption.
// Code changes for Leonardo (ECN01372).
// Code changes for formal verification tools (ECN01410).
// MOVX @Ri page address controllable from PORT2I if I/O ports ommitted (ECN01387).
//
// Revision 1.4  2000/02/20
// NINT0/1 sampling and condition zero ALU timing optimisation
//
// Revision 1.3  2000/02/05
// Name change repercussions
//
// Revision 1.2  1999/11/30
// More debug changes.
//
// Revision 1.1.1.1  1999/10/28
// "initialization and source check-in for m8051e"
//
// Revision 1.1  1999/10/22
// Initial revision
//
////////////////////////////////////////////////////////////////////////////////

`include "m8051w_cfg.v"

module m3s003dy (REG_RESULT, ACC_RESULT, B_RESULT, DPTR_RESULT, CARRY_RESULT,
//*******************************************************************       //
//IMPORTANT NOTICE                                                          //
//================                                                          //
//Copyright Mentor Graphics Corporation 1996 - 1999.  All rights reserved.  //
//This file and associated deliverables are the trade secrets,              //
//confidential information and copyrighted works of Mentor Graphics         //
//Corporation and its licensors and are subject to your license agreement   //
//with Mentor Graphics Corporation.                                         //
//                                                                          //
//Use of these deliverables for the purpose of making silicon from an IC    //
//design is limited to the terms and conditions of your license agreement   //
//with Mentor Graphics If you have further questions please contact Mentor  //
//Graphics Customer Support.                                                //
//                                                                          //
//This Mentor Graphics core (m8051w v2002.080) was extracted on             //
//workstation hostid 8316cbec Inventra                                      //
                 AUX_CARRY_RESULT,
                 OVERFLOW_RESULT, CONDITION_MET, OPERAND_A, OPERAND_B,
                 SAVE_ADDR, XRAMDI, PROGDI,
                 MULDIV_A, MULDIV_B, MULDIV_OV, CARRY_FLAG, ALU_CON, OPCODE,
                 BIT_ADDRESS);

  output [7:0] REG_RESULT;
  output [7:0] ACC_RESULT;
  output [7:0] B_RESULT;
  output [7:0] DPTR_RESULT;
  output CARRY_RESULT;
  output AUX_CARRY_RESULT;
  output OVERFLOW_RESULT;
  output CONDITION_MET;
  input  [7:0] OPERAND_A;
  input  [7:0] OPERAND_B;
  input  [7:0] SAVE_ADDR;
  input  [7:0] XRAMDI;
  input  [7:0] PROGDI;
  input  [7:0] MULDIV_A;
  input  [7:0] MULDIV_B;
  input  CARRY_FLAG;
  input  MULDIV_OV;
  input  [18:0] ALU_CON;
  input  [7:4] OPCODE;
  input  [2:0] BIT_ADDRESS;

  reg    [7:0] REG_RESULT;
  reg    [7:0] ACC_RESULT;
  reg    CARRY_RESULT;
  reg    AUX_CARRY_RESULT;
  reg    OVERFLOW_RESULT;
  reg    BIT_OPERAND;                     // bit operand sliced from OPERAND_B
  reg    RESULT_ZERO;
  reg    CONDITION_MET;                   // branch condition result

  wire   [7:0] B_RESULT;
  wire   [7:0] DPTR_RESULT;
  wire   [7:0] ALU_GEN;                   // ALU intermediate results from
  wire   [7:0] ALU_PROP;                  // sub-modules
  wire   [7:0] ALU_SUM;                          

  reg    CARRY_ENABLE;                     // local decode of ALU_CON
  reg    CARRY_IN;                         // qualified carry input to ALU logic
  reg    HI4_PROP, HI3_PROP, LO4_PROP;     // Carry propagate intermediates
  reg    HI4_GEN, HI3_GEN, LO4_GEN;        // Carry generate intermediates
  reg    CARRY_4, CARRY_7, CARRY_8;        // Carry results from 4, 7 and 8 bits
  reg    [7:0] ALU_RESULT;                 // Result of core ALU operations
  reg    ALU_OVERFLOW;                     // Overflow from addition/subtraction

  reg    BIT_RESULT;                       // ALU result for bit operand
 
  reg    [7:0] ROTATED_A;                  // rotated version of OPERAND_A
  reg    [7:0] ROTATED_CARRY;              // carry result of rotation

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//         Part 1: Core ALU arithmetic and logical functions                  //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// ALU primitive components: bit slice and 4-bit carry look-ahead units

  m3s001dy u1 (.P(ALU_PROP[0]), .CO(ALU_GEN[0]), .ALU_CON(ALU_CON[5:0]), 
     .A(OPERAND_A[0]), .B(OPERAND_B[0]));
  m3s001dy u2 (.P(ALU_PROP[1]), .CO(ALU_GEN[1]), .ALU_CON(ALU_CON[5:0]), 
     .A(OPERAND_A[1]), .B(OPERAND_B[1]));
  m3s001dy u3 (.P(ALU_PROP[2]), .CO(ALU_GEN[2]), .ALU_CON(ALU_CON[5:0]), 
      .A(OPERAND_A[2]), .B(OPERAND_B[2]));
  m3s001dy u4 (.P(ALU_PROP[3]), .CO(ALU_GEN[3]), .ALU_CON(ALU_CON[5:0]), 
      .A(OPERAND_A[3]), .B(OPERAND_B[3]));
  m3s001dy u5 (.P(ALU_PROP[4]), .CO(ALU_GEN[4]), .ALU_CON(ALU_CON[5:0]), 
      .A(OPERAND_A[4]), .B(OPERAND_B[4]));
  m3s001dy u6 (.P(ALU_PROP[5]), .CO(ALU_GEN[5]), .ALU_CON(ALU_CON[5:0]), 
      .A(OPERAND_A[5]), .B(OPERAND_B[5]));
  m3s001dy u7 (.P(ALU_PROP[6]), .CO(ALU_GEN[6]), .ALU_CON(ALU_CON[5:0]), 
      .A(OPERAND_A[6]), .B(OPERAND_B[6]));
  m3s001dy u8 (.P(ALU_PROP[7]), .CO(ALU_GEN[7]), .ALU_CON(ALU_CON[5:0]), 
      .A(OPERAND_A[7]), .B(OPERAND_B[7]));

  m3s002dy u9 (.S(ALU_SUM[3:0]), .P(ALU_PROP[3:0]), .G(ALU_GEN[2:0]), 
      .C_IN(CARRY_IN), .C_EN(CARRY_ENABLE));
  m3s002dy u10 (.S(ALU_SUM[7:4]), .P(ALU_PROP[7:4]), .G(ALU_GEN[6:4]), 
      .C_IN(CARRY_4), .C_EN(CARRY_ENABLE));

  // Produce the nibble-wide generates and propagates from the half-products
  // for use in generating carry results

  always @(ALU_PROP or ALU_GEN)
  begin: p_propgen
    HI4_PROP <= &ALU_PROP[7:4];
    HI3_PROP <= &ALU_PROP[6:4];
    LO4_PROP <= &ALU_PROP[3:0];

    LO4_GEN <= ALU_GEN[3]                     || ALU_GEN[2] && ALU_PROP[3] ||
               ALU_GEN[1] && (&ALU_PROP[3:2]) || ALU_GEN[0] && (&ALU_PROP[3:1]);
    HI4_GEN <= ALU_GEN[7]                     || ALU_GEN[6] && ALU_PROP[7] ||
               ALU_GEN[5] && (&ALU_PROP[7:6]) || ALU_GEN[4] && (&ALU_PROP[7:5]);
    HI3_GEN <= ALU_GEN[6]                     || ALU_GEN[5] && ALU_PROP[6] ||
               ALU_GEN[4] && (&ALU_PROP[6:5]);

    // assign zero flag for conditional jumps: CJNE, DJNZ, JZ and JNZ.
    RESULT_ZERO <= &ALU_PROP;
  end

  // Produce the 4-bit, 7-bit and 8-bit carry results for use by the
  // auxilliary, overflow and carry flags.
  // ALU_CON[5] inverts the carry for subtraction.

  always @(HI4_PROP or HI3_PROP or LO4_PROP or HI4_GEN or HI3_GEN or LO4_GEN or
           CARRY_IN or ALU_CON)
  begin: p_carry

    CARRY_4 <= LO4_GEN || CARRY_IN && LO4_PROP;
    CARRY_7 <= (HI3_GEN || LO4_GEN && HI3_PROP ||
               CARRY_IN && LO4_PROP && HI3_PROP) ^ ALU_CON[5];
    CARRY_8 <= (HI4_GEN || LO4_GEN && HI4_PROP ||
               CARRY_IN && LO4_PROP && HI4_PROP) ^ ALU_CON[5];
  end

  // Qualify carries according to opcode and invert for borrow operations.
  // ALU_CON[4] indicates an addition and ALU_CON[5] indicates subtraction.
  // ALU_CON[13] indicates addition or subtraction with carry/borrow.

  always @(CARRY_FLAG or CARRY_4 or CARRY_7 or CARRY_8 or ALU_CON)
  begin: p_flags

    CARRY_ENABLE     <= |ALU_CON[5:4];
    CARRY_IN         <= ALU_CON[5]? ~(CARRY_FLAG && ALU_CON[10]) 
                              : CARRY_FLAG && ALU_CON[10] && ALU_CON[4];

    AUX_CARRY_RESULT <= CARRY_4 ^ ALU_CON[5];
    ALU_OVERFLOW     <= CARRY_7 ^ CARRY_8;

  end


////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//         Part 2: Bit-wise operations on OPERAND_B and carry flag            //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  always @(OPERAND_B or BIT_ADDRESS)
  begin: p_bit_mux
    case (BIT_ADDRESS)
      3'd0:    BIT_OPERAND <= OPERAND_B[0];		
      3'd1:    BIT_OPERAND <= OPERAND_B[1];		
      3'd2:    BIT_OPERAND <= OPERAND_B[2];		
      3'd3:    BIT_OPERAND <= OPERAND_B[3];		
      3'd4:    BIT_OPERAND <= OPERAND_B[4];		
      3'd5:    BIT_OPERAND <= OPERAND_B[5];		
      3'd6:    BIT_OPERAND <= OPERAND_B[6];		
      3'd7:    BIT_OPERAND <= OPERAND_B[7];		
      default: BIT_OPERAND <= 1'bx;		
    endcase
  end

  // SINGLE BIT ALU ELEMENT USED FOR BIT OPERATIONS. 
  // ALU_CON CARRIES THE OPERATION CODE ACCORDING TO THE TABLE BELOW:
  //
  //   ALU_CON |  Operation
  //   6 7 8 9 |
  // ----------+---------------------
  //   0 0 0 0 |  return zero
  //   1 1 0 0 |  NOT carry
  //   0 1 1 1 |  CARRY OR BIT_OPERAND
  //   0 0 1 0 |  CARRY AND BIT_OPERAND
  //   1 0 1 1 |  CARRY OR NOT BIT_OPERAND
  //   0 0 0 1 |  CARRY AND NOT BIT_OPERAND
  //   0 0 1 1 |  pass CARRY
  //   0 1 1 0 |  pass BIT_OPERAND
  //   1 0 0 1 |  NOT BIT_OPERAND
  //   1 1 1 1 |  return one

  always @ (CARRY_FLAG or BIT_OPERAND or ALU_CON)
  begin : p_bit_op
    BIT_RESULT <= ~CARRY_FLAG && ~BIT_OPERAND && ALU_CON[6] ||
                  ~CARRY_FLAG &&  BIT_OPERAND && ALU_CON[7] ||
                   CARRY_FLAG &&  BIT_OPERAND && ALU_CON[8] ||
                   CARRY_FLAG && ~BIT_OPERAND && ALU_CON[9];
  end

  // Multiplex the selected bit result back into the ALU output path

  always @(ALU_CON or BIT_ADDRESS or BIT_RESULT or ALU_SUM)
  begin: p_alu_result
    if (ALU_CON[11] == 1) begin
      ALU_RESULT[0] <= BIT_ADDRESS == 4'd0 ? BIT_RESULT: ALU_SUM[0];
      ALU_RESULT[1] <= BIT_ADDRESS == 4'd1 ? BIT_RESULT: ALU_SUM[1];
      ALU_RESULT[2] <= BIT_ADDRESS == 4'd2 ? BIT_RESULT: ALU_SUM[2];
      ALU_RESULT[3] <= BIT_ADDRESS == 4'd3 ? BIT_RESULT: ALU_SUM[3];
      ALU_RESULT[4] <= BIT_ADDRESS == 4'd4 ? BIT_RESULT: ALU_SUM[4];
      ALU_RESULT[5] <= BIT_ADDRESS == 4'd5 ? BIT_RESULT: ALU_SUM[5];
      ALU_RESULT[6] <= BIT_ADDRESS == 4'd6 ? BIT_RESULT: ALU_SUM[6];
      ALU_RESULT[7] <= BIT_ADDRESS == 4'd7 ? BIT_RESULT: ALU_SUM[7];
    end
    else
      ALU_RESULT <= ALU_SUM;
  end

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//         Part 3: Accumulator swaps and rotates                              //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// These operations affect the accumulator (input on OPERAND_A) and carry only.

// The four rotate operations: RL, RLC, RR and RRC.
  always @(OPCODE or OPERAND_A or  CARRY_FLAG)
  begin: p_rotate
    if (OPCODE[5] == 1) begin
      // Rotate accumulator left
      ROTATED_A[7:1] <= OPERAND_A[6:0];
      // Switch LSB and carry source if RLC 
      ROTATED_A[0]   <= OPCODE[4] ? CARRY_FLAG: OPERAND_A[7]; 
      ROTATED_CARRY  <= OPCODE[4] ? OPERAND_A[7]: CARRY_FLAG; 
    end
    else begin
      // Rotate accumulator right
      ROTATED_A[6:0] <= OPERAND_A[7:1];
      // Switch MSB and carry source if RRC 
      ROTATED_A[7]   <= OPCODE[4] ? CARRY_FLAG: OPERAND_A[0]; 
      ROTATED_CARRY  <= OPCODE[4] ? OPERAND_A[0]: CARRY_FLAG; 
    end
  end

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//         Part 4: Accumulator and carry results multiplexers                 //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
  
  // The result coding is as follows:

  //  ALU_CON | ACCUMULATOR RESULT
  // 14 13 12 |                   
  // ---------+-------------------
  //          |                   
  //  0  0  0 | ALU_RESULT        
  //  0  0  1 | XCH(OP_A, OP_B)   
  //  0  1  0 | XCHD(OP_A, OP_B)  
  //  0  1  1 | SWAP(OP_A)        
  //  1  0  0 | MUL/DIV A RESULT  
  //  1  0  1 | PROGRAM MEMORY DATA (PROGDI)
  //  1  1  0 | ROTATED A RESULT  
  //  1  1  1 | EXTERNAL RAM DATA (XRAMDI or PROGDI)

  always @(ALU_RESULT or OPERAND_A or OPERAND_B or MULDIV_A or ROTATED_A or
           CARRY_8 or CARRY_FLAG or ROTATED_CARRY or BIT_RESULT or PROGDI or
           XRAMDI or SAVE_ADDR or MULDIV_OV or ALU_OVERFLOW or ALU_CON)
  begin: p_acc_result

    // ALU result for the accumulator
    case(ALU_CON[14:12])
      3'b000:  ACC_RESULT <= ALU_RESULT;
      3'b001:  ACC_RESULT <= OPERAND_B;
      3'b010:  ACC_RESULT <= {OPERAND_A[7:4], OPERAND_B[3:0]};
      3'b011:  ACC_RESULT <= {OPERAND_A[3:0], OPERAND_A[7:4]};
      3'b100:  ACC_RESULT <= MULDIV_A;
      3'b101:  ACC_RESULT <= PROGDI;
      3'b110:  ACC_RESULT <= ROTATED_A;
  `ifdef muxed_pxram
      3'b111:  ACC_RESULT <= PROGDI;
  `else
      3'b111:  ACC_RESULT <= XRAMDI;
  `endif
      default: ACC_RESULT <= 8'hxx;
    endcase

    // ALU result for register memory        
    // ALU_CON | REGISTER RESULT              | OVERFLOW RESULT
    //  16 15  |                              |
    //  -------+---------------------------------------------------------
    //         |                              |
    //   0  0  | ALU_RESULT                   | ALU OVERFLOW
    //   0  1  | XCHD(OP_A, OP_B)             | ALU OVERFLOW
    //   1  0  | MUL/DIV B RESULT             | MULTIPLIER OVERFLOW
    //   1  1  | PROGRAM ADDRESS TO BE SAVED  | MULTIPLIER OVERFLOW

    case(ALU_CON[16:15])
      2'b00:   REG_RESULT <= ALU_RESULT;
      2'b01:   REG_RESULT <= {OPERAND_B[7:4], OPERAND_A[3:0]};
      2'b10:   REG_RESULT <= 8'h00;
      2'b11:   REG_RESULT <= SAVE_ADDR;
      default: REG_RESULT <= 8'hxx;
    endcase

    // Multiplex carry flag results

    // ALU_CON| CARRY RESULT
    //  18 17 |            
    //  ------+-----------
    //        |               
    //   0  0 | ALU_CARRY 
    //   0  1 | DAA CUMULATIVE CARRY
    //   1  0 | BIT RESULT
    //   1  1 | ROTATED CARRY  

    case(ALU_CON[18:17])
      2'b00:   CARRY_RESULT <= CARRY_8;
      2'b01:   CARRY_RESULT <= CARRY_8 || CARRY_FLAG;
      2'b10:   CARRY_RESULT <= BIT_RESULT;
      2'b11:   CARRY_RESULT <= ROTATED_CARRY;
      default: CARRY_RESULT <= 8'hxx;
    endcase

    // Multiply and divide give the overflow flag special results
    OVERFLOW_RESULT <= ALU_CON[16]? MULDIV_OV: ALU_OVERFLOW;

  end

  // Special B register data path to help Synopsys synthesis
  assign B_RESULT = (ALU_CON[16:15] == 2'b10)? MULDIV_B: REG_RESULT;

  // Fast data pointer result path 
  assign DPTR_RESULT = ALU_SUM;

  // Branch condition multiplexer
  // CJNE & DJNZ use RESULT_ZERO 

  always @(BIT_OPERAND or CARRY_FLAG or RESULT_ZERO or OPCODE)
  begin: p_cmet
 
    if(OPCODE[7])
      CONDITION_MET <= ~RESULT_ZERO;
    else
      case (OPCODE[6:4])
        3'b000,
        3'b001,
        3'b010:  CONDITION_MET <=  BIT_OPERAND;
        3'b011:  CONDITION_MET <= ~BIT_OPERAND;
        3'b100:  CONDITION_MET <=  CARRY_FLAG;
        3'b101:  CONDITION_MET <= ~CARRY_FLAG;
        3'b110:  CONDITION_MET <=  RESULT_ZERO;
        default: CONDITION_MET <= ~RESULT_ZERO;
      endcase
  end

endmodule
